package com.leo.component;

import com.almasb.fxgl.core.util.LazyValue;
import com.almasb.fxgl.dsl.FXGL;
import com.almasb.fxgl.dsl.components.EffectComponent;
import com.almasb.fxgl.entity.Entity;
import com.almasb.fxgl.entity.EntityGroup;
import com.almasb.fxgl.entity.SpawnData;
import com.almasb.fxgl.entity.component.Component;
import com.almasb.fxgl.time.LocalTimer;
import com.leo.common.Config;
import com.leo.common.Dir;
import com.leo.common.GameType;
import com.leo.effects.FreezeEffect;
import com.leo.effects.ShipEffect;

import java.util.List;

import static com.leo.common.Config.TANK_MOVE_SPEED;

/**
 * 坦克组件
 */
public class TankComponent extends Component {

    /**
     * 当前帧是否在移动
     */
    private boolean movedThisFrame = false;

    /**
     * 每一帧的移动距离
     */
    private double distance;

    /**
     * 移动方向
     */
    private Dir moveDir = Dir.UP;

    /**
     * 射击计时器
     */
    private LocalTimer shootTimer;

    private LazyValue<EntityGroup> blockAllLazyValue = new LazyValue<>(() ->
            FXGL.getGameWorld().getGroup(GameType.BORDER, GameType.BRICK, GameType.STONE, GameType.SEA, GameType.PLAYER, GameType.ENEMY)
    );

    private LazyValue<EntityGroup> blockLazyValue = new LazyValue<>(() ->
            FXGL.getGameWorld().getGroup(GameType.BORDER, GameType.BRICK, GameType.STONE, GameType.PLAYER, GameType.ENEMY)
    );
    private EffectComponent effectComponent;

    @Override
    public void onAdded() {
        shootTimer = FXGL.newLocalTimer();
    }

    /**
     * tpf 代表这一帧的用时；一般来说，60帧每一秒
     * <p>
     * 移动的距离是一个变量 时间 * 速度 = 距离
     *
     * @param tpf time per frame
     */
    @Override
    public void onUpdate(double tpf) {
        if (effectComponent.hasEffect(FreezeEffect.class)) {
            return;
        }
        movedThisFrame = false;
        distance = tpf * TANK_MOVE_SPEED;
    }

    /**
     * 向上移动
     */
    public void moveUp() {
        if (movedThisFrame) {
            return;
        }
        movedThisFrame = true;
        entity.setRotation(0);
        moveDir = Dir.UP;
        move();
    }

    /**
     * 向下移动
     */
    public void moveDown() {
        if (movedThisFrame) {
            return;
        }
        movedThisFrame = true;
        entity.setRotation(180);
        moveDir = Dir.DOWN;
        move();
    }

    /**
     * 向左移动
     */
    public void moveLeft() {
        if (movedThisFrame) {
            return;
        }
        movedThisFrame = true;
        entity.setRotation(270);
        moveDir = Dir.LEFT;
        move();
    }

    /**
     * 向右移动
     */
    public void moveRight() {
        if (movedThisFrame) {
            return;
        }
        movedThisFrame = true;
        entity.setRotation(90);
        moveDir = Dir.RIGHT;
        move();
    }

    /**
     * 射击
     */
    public void shoot() {
        // 如果超过了指定时间则可以射击
        if (shootTimer.elapsed(Config.SHOOT_DELAY)) {
            FXGL.spawn("bullet",
                    new SpawnData(entity.getCenter().subtract(8 / 2.0, 10 / 2.0))
                            .put("dir", moveDir.getVector())
                            .put("ownerType", entity.getType())
                            .put("level", entity.getComponent(TankLevelComponent.class).getValue())
            );
            // 定时器归零
            shootTimer.capture();
        }
    }

    /**
     * 移动的过程中检测碰撞
     */
    public void move() {
        int len = (int) distance;
        effectComponent = entity.getComponent(EffectComponent.class);
        boolean hasShip = effectComponent.hasEffect(ShipEffect.class);
        // 获取所有的碰撞物
        List<Entity> blockList = blockAllLazyValue.get().getEntitiesCopy();
        if (hasShip) {
            blockList = blockLazyValue.get().getEntitiesCopy();
        }
        // 从list中删除掉自己，不然会导致自己和自己纠缠
        blockList.remove(entity);
        // 是否碰撞
        boolean isCollision = false;
        for (int i = 0; i < len; i++) {
            // 一个像素一个像素的移动
            entity.translate(moveDir.getVector().getX(), moveDir.getVector().getY());
            // 一个一个检测碰撞
            for (Entity block : blockList) {
                if (entity.isColliding(block)) {
                    isCollision = true;
                    break;
                }
            }

            // 如果碰撞了，则退回一个像素，并结束循环
            if (isCollision) {
                entity.translate(-moveDir.getVector().getX(), -moveDir.getVector().getY());
                break;
            }
        }
    }

    public Dir getMoveDir() {
        return moveDir;
    }

    public void setMoveDir(Dir moveDir) {
        this.moveDir = moveDir;
    }
}
